<?php

    class WZ_Locale
    {
        const DEFAULT_LOCALE    = 'fr_FR';
        const DEFAULT_CURRENCY  = 'EUR';
        const DEFAULT_TIMEZONE  = 'Europe/Paris';

        /**
         * Set locale and language if possible
         *
         * @static
         * @param string (locale or language) $locale
         */
        public static function setLocale($locale = 'auto')
        {
            if (Zend_Registry::isRegistered('Zend_Locale')) {
                $currentLocale = Zend_Registry::get('Zend_Locale');
                if ($locale === $currentLocale->toString()) {
                    return;
                }
            }

            if (WZ_Area::isInstaller()) {

                $session = WZ::session('install');

                if (Zend_Registry::isRegistered('Zend_Locale')) {
                    $currentLocale = Zend_Registry::get('Zend_Locale');
                } else {
                    $currentLocale = new Zend_Locale();
                    Zend_Locale::setCache(WZ::cache());
                    Zend_Registry::set('Zend_Locale', $currentLocale);
                }

                if ($currentLocale->isLocale($locale)) {
                    $currentLocale->setLocale($locale);
                }
                $session->current_locale = $locale;
                return;
            }

            $session = WZ::session();

            if (!strstr($locale, '_')) {
                $locale = self::_getLocaleFromLanguageCode($locale);
            }

            if (Zend_Registry::isRegistered('Zend_Locale')) {
                $currentLocale = Zend_Registry::get('Zend_Locale');
                $currentLocale->setLocale($locale);
            } else {
                try {
                    $currentLocale = new Zend_Locale($locale);
                } catch (Zend_Locale_Exception $e) {
                    $currentLocale = new Zend_Locale(self::DEFAULT_LOCALE);
                }
                Zend_Locale::setCache(WZ::cache());
                Zend_Registry::set('Zend_Locale', $currentLocale);
            }

            $availableLanguages = WZ::single('locale/language')
                ->select(array('locale', 'id'))
                ->fetchPairs();

            if (WZ_Area::isBackend()) {

                $session->locale = $locale;
                $defaultLanguage = WZ::config('locale/main/language_admin');
                if (array_search($defaultLanguage, $availableLanguages)) {
                    $session->language = $defaultLanguage;
                } else {
                    $session->language = current($availableLanguages);
                }
            } else {
                $localeCode = $currentLocale->toString();
                if (isset($availableLanguages[$localeCode])) {
                    $session->language = $availableLanguages[$localeCode];
                } else {
                    $defaultLanguage = WZ::config('locale/main/language_front');
                    if (array_search($defaultLanguage, $availableLanguages)) {
                        $session->language = $defaultLanguage;
                    } else {
                        $session->language = current($availableLanguages);
                    }
                }
            }

            self::setTimezone();
        }

        /**
         * Retrieve first suitable locale with language
         *
         * @static
         * @param string $code Language ISO code
         * @return string Locale ISO code
         */
        private static function _getLocaleFromLanguageCode($code)
        {
            if (!empty($code)) {
                $localeList = self::getLocaleList(true);
                foreach ($localeList as $locale) {
                    if (strpos($locale, $code) === 0) {
                        return $locale;
                    }
                }
            }

            return self::DEFAULT_LOCALE;
        }

        /**
         * Retrieve locale object
         *
         * @static
         * @return Zend_Locale
         */
        public static function getLocale()
        {
            if (!Zend_Registry::isRegistered('Zend_Locale')) {

                if (WZ_Area::isFrontend()
                    && WZ_Controller_Router_Route_Front::hasLocaleInUrl()) {

                    self::setLocale(WZ_Controller_Router_Route_Front::getCurrentLocale());

                } elseif (WZ_Area::isBackend()
                    && isset(WZ::session()->locale)) {

                    self::setLocale(WZ::session()->locale);
                } elseif (WZ_Area::isInstaller()
                    && isset(WZ::session('install')->current_locale)) {

                    self::setLocale(WZ::session('install')->current_locale);
                } elseif (WZ_Area::isInstaller()) {

                    self::setLocale(self::DEFAULT_LOCALE);
                } else {

                    self::setLocale(WZ::config('locale/main/locale'));
                }
            }
            return Zend_Registry::get('Zend_Locale');
        }

        /**
         * Retrieve default locale from config
         *
         * @static
         * @return string Locale ISO code
         */
        public static function getDefaultLocale()
        {
            return WZ::config('locale/main/locale');
        }

        /**
         * Returns a list of all known locales, or all installed locales
         *
         * @param $installedOnly bool
         * @static
         * @return array
         */
        public static function getLocaleList($installedOnly = false)
        {
            if (!$installedOnly) {
                return array_keys(Zend_Locale::getLocaleList());
            }
            return WZ::single('locale/language')->getLocaleList();
        }

        /**
         * @static
         * @return array
         */
        public static function getInstallLocaleList()
        {
            $options = array();

            $locales = Zend_Locale::getLocaleList();
            $languages = Zend_Locale::getTranslationList('language', self::getLocale());
            $countries = Zend_Locale::getTranslationList('territory', self::getLocale(), 2);

            foreach ($locales as $code => $is_active) {
                if (strstr($code, '_')) {
                    $data = explode('_', $code);
                    if (!isset($languages[$data[0]]) || !isset($countries[$data[1]])) {
                        continue;
                    }
                    $options[$code] = ucfirst($languages[$data[0]]) . ' (' . $countries[$data[1]] . ')';
                }
            }
            return $options;
        }

        /**
         * Retrieve languageId from session;
         *
         * @static
         * @return int
         */
        public static function getLanguageId()
        {
            if (!isset(WZ::session()->language)) {
                if (WZ_Area::isBackend()) {

                    WZ::session()->language = WZ::config('locale/main/language_admin');
                } else {
                    WZ::session()->language = WZ::config('locale/main/language_front');
                }
            }
            return WZ::session()->language;
        }

        /**
         * Retrieve part of url, responsible for locale
         *
         * @static
         * @param string $locale Locale ISO code
         * @return string Part of url ('/uk')
         */
        public static function getLanguageUrl($locale = null)
        {
            if (null !== $locale) {
                list($language) = explode('_', $locale);
            } else {
                $language = self::getLocale()->getLanguage();
                $locale   = self::getLocale()->toString();
            }

            if ($locale == self::getDefaultLocale()) {
                return '';
            }
            if ($locale == self::_getLocaleFromLanguageCode($language)) {
                return '/' . $language;
            }

            return '/' . $locale;
        }

        /**
         * get default store timezone
         *
         * @static
         * @return  string  example : "Australia/Hobart"
         */
        public static function getDefaultTimezone()
        {
            return WZ::config('locale/main/timezone');
        }

        /**
         * get timezone
         *
         * @static
         * @return string
         */
        public static function getTimezone()
        {
            return date_default_timezone_get();
        }

        /**
         * set timezone
         *
         * @static
         * @param mixed void|string
         * @return bool
         */
        public static function setTimezone($timezone = null)
        {
            if (null === $timezone) {
                $timezone = WZ::config('locale/main/timezone');
            }
            if (@date_default_timezone_set($timezone)) {
                return true;
            }
            return @date_default_timezone_set(self::DEFAULT_TIMEZONE);
        }

        /**
         * Retrieve the list of available admin intrerface tranlations
         *
         * @static
         * @return array
         */
        public static function getAdminLocales()
        {
            if (!$locales = WZ::cache()->load('locales_list')) {
                $path = WZ::config()->system->path . '/app/locale';

                try {
                    $locales_dir = new DirectoryIterator($path);
                } catch (Exception $e) {
                    throw new WZ_Exception("Directory $path not readable");
                }

                $locale = WZ_Locale::getLocale();
                $locales = array();

                foreach ($locales_dir as $localeDir) {
                    $localeCode = $localeDir->getFilename();
                    if ($localeCode[0] == '.' || !strstr($localeCode, '_')) {
                        continue;
                    }
                    list($language, $country) = explode('_', $localeCode, 2);

                    $language = $locale->getTranslation($language, 'language', $localeCode);
                    $country = $locale->getTranslation($country, 'country', $localeCode);
                    if (!$language) {
                        $language = $locale->getTranslation(
                            $language, 'language', WZ_Locale::DEFAULT_LOCALE
                        );
                    }
                    if (!$country) {
                        $country = $locale->getTranslation(
                            $country, 'country', WZ_Locale::DEFAULT_LOCALE
                        );
                    }
                    $locales[$localeCode] = ucfirst($language) . ' (' . $country . ')';
                }
                ksort($locales);
                WZ::cache()->save($locales, 'locales_list', array('locales'));
            }
            return $locales;
        }

        /**
         * Retrieve array of available translations
         *
         * @return array
         */
        public static function getAvailableLocales()
        {
            $path = WZ_ROOT . '/app/locale/';

            try {
                $localeDir = new DirectoryIterator($path);
            } catch (Exception $e) {
                throw new WZ_Exception("Directory $path not readable");
            }

            $currentLocale = self::getLocale();
            $locales = array();

            foreach ($localeDir as $locale) {
                if ($locale->isDot() || !$locale->isDir()) {
                    continue;
                }
                $localeName = $locale->getFilename();
                list($language, $country) = explode('_', $localeName, 2);

                $language = $currentLocale->getTranslation($language, 'language', $localeName);
                $country = $currentLocale->getTranslation($country, 'country', $localeName);
                if (!$language) {
                    $language = $currentLocale->getTranslation($language, 'language', 'en_US');
                }
                if (!$country) {
                    $country = $currentLocale->getTranslation($country, 'country', 'en_US');
                }
                $locales[$localeName] = ucfirst($language) . ' (' . $country . ')';
            }
            ksort($locales);

            return $locales;
        }

        /**
         *
         * @static
         * @return array
         */
        public static function getTimeZoneList()
        {
            $options = array();
            $zones = Zend_Locale::getTranslationList('WindowsToTimezone', self::getLocale());

            asort($zones);
            foreach ($zones as $code => $name) {
                $name = trim($name);
                $options[$code] = empty($name) ? $code : $name . ' (' . $code . ')';
            }
            return $options;
        }

        /**
         * @static
         * @return array
         */
        public static function getCurrencyList()
        {
            return Zend_Locale::getTranslationList('NameToCurrency', self::getLocale());
        }

        /**
         * Returns number from string
         *
         * @param string $value
         * @return float
         */
        public static function getNumber($value)
        {
            if (null === $value) {
                return null;
            }

            if (!is_string($value)) {
                return floatval($value);
            }

            $value = str_replace('\'', '', $value);
            $value = str_replace(' ', '', $value);
            $value = str_replace(',', '.', $value);

            return floatval($value);
        }
    }
